package com.graphhopper.util.buffer;




import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;


/**
 * @author: heguanglong
 * @date: 2020-12-22
 **/
public class RegionUtil {
    private static double EARTH_RADIUS = 6378137;

    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    public static boolean polygonCheck(String point,String  polygon){
        String[] locationArray = point.split("\\,");
        Double lon = new Double(locationArray[0]);
        Double lat = new Double(locationArray[1]);
        return isInPolygon(lon,lat,polygon);
    }
    /**
     * 判断是否在多边形区域内
     *
     * @param pointLon 要判断的点的横坐标 经度
     * @param pointLat 要判断的点的纵坐标 维度
     * @return
     */
    public static boolean isInPolygon(double pointLon, double pointLat,String  latLons) {
        // 将要判断的横纵坐标组成一个点
        Point2D.Double point = new Point2D.Double(pointLon, pointLat);
        // 将区域各顶点的横纵坐标放到一个点集合里面
        List<Point2D.Double> pointList = new ArrayList<Point2D.Double>();
        double v = 0.0, v1 = 0.0;
        String[] strings=latLons.split("\\;");
        for (int i = 0; i < strings.length; i++) {
            String[] arr=strings[i].split("\\,");
            v = Double.valueOf(arr[0]);
            v1 = Double.valueOf(arr[1]);
            Point2D.Double polygonPoint = new Point2D.Double(v, v1);
            pointList.add(polygonPoint);
        }
        return isPtInPoly(point, pointList);
    }


    public static boolean isInCircle(String gps, String centerGps, Double radius){
        String[] gpsArr=gps.split("\\,");
        String[] centerGpsArr=centerGps.split("\\,");
        return  isInCircle(Double.valueOf(gpsArr[0]),Double.valueOf(gpsArr[1]),Double.valueOf(centerGpsArr[0]),Double.valueOf(centerGpsArr[1]),radius);
    }

    public static void main(String[] args) {
        //str
         String value="116.38172256949406,39.85367623549223,116.61586868765761,40.01899429690533";
         //判断是否在矩形内
         String str="116.38172256949406,39.85367623549223";
         String[] arr=str.split("\\,");
         System.out.println(RegionUtil.isInPolygon(Double.valueOf(arr[0]), Double.valueOf(arr[1]),value));

         //判断是否在矩形外
        str="116.2689692038,39.987596252983";
        arr=str.split("\\,");
        System.out.println(RegionUtil.isInPolygon(Double.valueOf(arr[0]), Double.valueOf(arr[1]),value));

        //判断是否在圆形
        //中心点左边
        value="116.45469261511556,39.91861260022645";
        //半径：
        double radius=74;
        str="116.453902662,39.918886696";
        System.out.println("断是否在圆形内:"+RegionUtil.isInCircle(str,value,radius));


        //判断是否在圆形外
        str="115.791798826,40.125459986";
        System.out.println("断是否在圆形外:"+RegionUtil.isInCircle(str,value,radius));
    }



    /**
     * 返回一个点是否在一个多边形区域内， 如果点位于多边形的顶点或边上，不算做点在多边形内，返回false
     * @param point
     * @param polygon
     * @return
     */
    public static boolean checkWithJdkGeneralPath(Point2D.Double point, List<Point2D.Double> polygon) {
        java.awt.geom.GeneralPath p = new java.awt.geom.GeneralPath();
        Point2D.Double first = polygon.get(0);
        p.moveTo(first.x, first.y);
        polygon.remove(0);
        for (Point2D.Double d : polygon) {
            p.lineTo(d.x, d.y);
        }
        p.lineTo(first.x, first.y);
        p.closePath();
        return p.contains(point);
    }


    /**
     * 判断点是否在多边形内，如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
     * @param point 检测点
     * @param pts   多边形的顶点
     * @return      点在多边形内返回true,否则返回false
     */
    public static boolean isPtInPoly(Point2D.Double point, List<Point2D.Double> pts){

        int n = pts.size();
        boolean boundOrVertex = true;
        int intersectCount = 0;
        double precision = 2e-10;
        Point2D.Double p1, p2;
        Point2D.Double p = point;

        p1 = pts.get(0);
        for(int i = 1; i <= n; ++i){
            if(p.equals(p1)){
                return boundOrVertex;
            }
            p2 = pts.get(i % n);
            if(p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)){
                p1 = p2;
                continue;
            }

            if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){
                if(p.y <= Math.max(p1.y, p2.y)){
                    if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){
                        return boundOrVertex;
                    }

                    if(p1.y == p2.y){
                        if(p1.y == p.y){
                            return boundOrVertex;
                        }else{
                            ++intersectCount;
                        }
                    }else{
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
                        if(Math.abs(p.y - xinters) < precision){
                            return boundOrVertex;
                        }

                        if(p.y < xinters){
                            ++intersectCount;
                        }
                    }
                }
            }else{
                if(p.x == p2.x && p.y <= p2.y){
                    Point2D.Double p3 = pts.get((i+1) % n);
                    if(p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)){
                        ++intersectCount;
                    }else{
                        intersectCount += 2;
                    }
                }
            }
            p1 = p2;
        }

        if(intersectCount % 2 == 0){
            return false;
        } else {
            return true;
        }
    }

    /**
     * 通过经纬度获取距离(单位：米)
     *
     * @param lat1 纬度1
     * @param lng1 经度1
     * @param lat2 纬度2
     * @param lng2 经度2
     * @return 距离
     */
    public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        return s;
    }

    /**
     * @param lat1   纬度
     * @param lat2   纬度
     * @param lng1   经度
     * @param lng2   经度
     * @param radius 判断一个点是否在圆形区域内,比较坐标点与圆心的距离是否小于半径
     */
    public static boolean isInCircle(double lng1, double lat1, double lng2, double lat2, double radius) {
        double distance = getDistance(lat1, lng1, lat2, lng2);
        if (distance > radius) {
            return false;
        } else {
            return true;
        }
    }




}
